package com.zeroes.cons;





import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.Vector;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.Matrix;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.opengl.GLSurfaceView;
import android.util.Log;

import org.zeroes.common_prelude.*;


public class ZSRenderer implements GLSurfaceView.Renderer {

	public static final int MAX_VERTICES = 8000;
	public static final int MAX_INDICES = (MAX_VERTICES / 2) * 3;		// 6 indices for every 4 vertices
	
	public static final int BATCH_NULL = 0;
	public static final int BATCH_QUAD = 1;
	public static final int BATCH_SETTEXTURE = 2;
	public static final int BATCH_SETOPACITY = 3;
	public static final int BATCH_SETBLEND = 4;
	public static final int BATCH_UPDATEMODELVIEW = 5;
	public static final int BATCH_RENDERTOTEXTURE = 6;
	public static final int BATCH_CLEAR = 7;
	
	public static final int SURFACE_CHANGED_SIZE = 0; 
	public static final int CAN_START_ASSET_LOADING = 1; 

	public Shader currentShader;
	public Shader colorShader;
	public int lastSrcBlend = GLES20.GL_ONE;
	public int lastDestBlend = GLES20.GL_ONE_MINUS_SRC_ALPHA;
	
	public Mat4 mPMatrix;  
	public float[] MVPMatrix; 
	// test construct
	private int[] cam = {0, 0, 100};			// camera position
	private int[] look = {0, 0, 0};				// lookat position
	private int[] up = {0, 1, 0};				// up vector
	private float[] worldScale = {1, 1, 1};
    
	public Mat4 matP ;
	public Mat4 matMV;
	public int sz=0;
	private boolean gameInitialized = false;
	  private GameLoop loop;
	public ZSRenderer(Context context)
    {
        mContext = context;
        ZSGameManager.AskMe().setContext(context);
        mPMatrix = new Mat4();
       MVPMatrix = new float[16];
       Matrix.setIdentityM(MVPMatrix, 0);
   	matP = new Mat4();
   	matMV = new Mat4();
    Matrix.setIdentityM(matP.data, 0);
    Matrix.setIdentityM(matMV.data, 0);
   	sz=0;
    }
    
      
 
    ///
    // Initialize the shader and program object
    //
    public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
    {
    	Log.v("gtrans", "ON SURFACE CREATED");
		try {
			currentShader= new Shader(R.raw.simple_vs, R.raw.simple_ps, mContext, true, 1); 
		} catch (Exception e) {
			Log.d("SHADER 0 SETUP", e.getLocalizedMessage());
		}
                                               
		try {
			colorShader= new Shader(R.raw.simple_vs, R.raw.simple_ps, mContext, false, 0); 
		} catch (Exception e) {
			Log.d("SHADER 0 SETUP", e.getLocalizedMessage());
		}      
        // Load the shaders and get a linked program object
        mProgramObject = currentShader.get_program();
        this.mColorProgramObject=colorShader.get_program();
        GLES20.glClearColor(1.0f, 0.87f, 0.23f, 1.0f);
        
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
		//gl.colorMask(1, 1, 1, 0);
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glDisable(GLES20.GL_CULL_FACE);
        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
     
        GLES20.glDisable(GLES20.GL_DEPTH_TEST);
       // this.matMV = Mat4.lookAt(cam[0],cam[1],cam[2], look[0],look[1],look[2],up[0],up[1],up[2]);
        Matrix.setLookAtM(this.matMV.data, 0, 0, 0, 100, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
       
       // ZSGameManager.AskMe().buildScene();
        ZSGameManager.AskMe().notify(CAN_START_ASSET_LOADING);
        //ZSGameManager.AskMe().toRun(new MyGame());
    }

    // /
    // Draw a triangle using the shader pair created in onSurfaceCreated()
    //
    
    private void project(float x,float y, float[] out, int ww, int hh){
        int[] viewport = {0, 0, 0, 0};
    
        	viewport[2]=mWidth; 
        	viewport[3]=mHeight; 


        	float[] mv = this.matMV.data;
		float[] proj = this.matP.data;
		
		// Based on http://www.opengl.org/wiki/GluProject_and_gluUnProject_code
		float[] fTempo = {0, 0, 0, 0, 0, 0, 0, 0};
		
		fTempo[0] = mv[0]*x+mv[4]*y+mv[12];
		fTempo[1] = mv[1]*x+mv[5]*y+mv[13];
		fTempo[2] = mv[2]*x+mv[6]*y+mv[14];
		fTempo[3] = mv[3]*x+mv[7]*y+mv[15];

		fTempo[4] = proj[0]*fTempo[0]+proj[4]*fTempo[1]+proj[8]*fTempo[2]+proj[12]*fTempo[3];
		fTempo[5] = proj[1]*fTempo[0]+proj[5]*fTempo[1]+proj[9]*fTempo[2]+proj[13]*fTempo[3];
		fTempo[6] = proj[2]*fTempo[0]+proj[6]*fTempo[1]+proj[10]*fTempo[2]+proj[14]*fTempo[3];
		fTempo[7] = -fTempo[2];
		
		// The result normalizes between -1 and 1
		if(fTempo[7]==0.0)	//The w value
			return ;
		 
		fTempo[7]=1.0f/fTempo[7];

		fTempo[4]*=fTempo[7];
		fTempo[5]*=fTempo[7];
		fTempo[6]*=fTempo[7];

		out[0]=(fTempo[4]*0.5f+0.5f)*viewport[2]+viewport[0];
		out[1]=(fTempo[5]*0.5f+0.5f)*viewport[3]+viewport[1];
    	
    	
    	
    	
    	return ;
    }
    
    
    	
    
    public void resetMV(){
    	float zeye   = (mHeight / 1.1566f);
    	
		//mat4.scale(this.matMV, this.worldScale);
    	Matrix.setIdentityM(this.matMV.data, 0);
    	//this.matMV = Mat4.lookAt(mWidth/2,mHeight/2,zeye, mWidth/2,mHeight/2,0,up[0],up[1],up[2]);
    	Matrix.setLookAtM(this.matMV.data, 0, 0, 0, 100, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    	Matrix.scaleM(this.matMV.data, 0, worldScale[0], worldScale[1], 1);
    	//GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(mProgramObject, "matMV"), 1, false, this.matMV.data, 0);
    	//GLES20.glViewport(0, 0, mWidth, mHeight);
    }
    public void onDrawFrame(GL10 glUnused)
    {
        // Set the viewport
    	// GLES20.glViewport(0, 0, mWidth, mHeight);
        // Clear the color buffer
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
	     
    // ZSGameManager.AskMe().tick();
        if (!gameInitialized) {

            loop = new GameLoop();
            loop.start();
            gameInitialized = true;
          }
          // Handle updating, clearing the screen, and drawing
          if (loop.running() && gameInitialized)
            loop.run();
      
        
    }

    ///
    // Handle surface changes
    //
    public void onSurfaceChanged(GL10 glUnused, int width, int height)
    {
    //	Log.v("gtrans", "ON SURFACE CHANGED");
    	this.worldScale[0] =1;
    	this.worldScale[1] =1;
        this.sz++;
        
        mWidth = width;
        mHeight = height;
        GLES20.glViewport(0, 0, mWidth, mHeight);
        ZSGameManager.AskMe().notify(SURFACE_CHANGED_SIZE);
		float ratio = (float) width / height;

        Matrix.frustumM(this.matP.data, 0, -ratio, ratio, -1, 1, 0.5f, 1000);
        
		//this.matMV = Mat4.lookAt(mWidth/2,mHeight/2,zeye, mWidth/2,mHeight/2,0,up[0],up[1],up[2]);
		float[] tl = {0, 0};
		float[] br = {0, 0};
		//Matrix.setLookAtM(this.matMV.data, 0, 0, 0, 100, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
	this.project(0, 1,tl,400,400);
	this.project(1, 0,br,400,400);
		
		this.worldScale[0] = 1.0f / (br[0] - tl[0]);
		this.worldScale[1] = -1 / (br[1] - tl[1]);
    
    	Matrix.scaleM(this.matMV.data, 0, worldScale[0], worldScale[1], 1);
      //  resetMV();
    }

    
    
    // Handle to a program object
    public int mProgramObject;
    public int mColorProgramObject;
    
    // Attribute locations
    private int mPositionLoc;
    private int mTexCoordLoc;
    
    // Sampler location
    private int mBaseMapLoc;
    private int mLightMapLoc;
    
    // Texture handle
    private int mBaseMapTexId;
    private int mLightMapTexId;
    
    // Additional member variables
    public int mWidth;
    public int mHeight;
    private FloatBuffer mVertices;
    private ShortBuffer mIndices;
    public Context mContext;
    private FloatBuffer _verts;
    private ShortBuffer indices;
    private final float[] mVerticesData =
    { 
            -0.5f, 0.5f, 0.0f, // Position 0
            0.0f, 0.0f, // TexCoord 0
            -0.5f, -0.5f, 0.0f, // Position 1
            0.0f, 1.0f, // TexCoord 1
            0.5f, -0.5f, 0.0f, // Position 2
            1.0f, 1.0f, // TexCoord 2
            0.5f, 0.5f, 0.0f, // Position 3
            1.0f, 0.0f // TexCoord 3
    };

    private final short[] mIndicesData =
    { 
            0, 1, 2, 0, 2, 3 
    };
    
    public void pause(){
    	
    	this.loop.pause();
    }
    public void resume(){
    	
    	this.loop.resume();
    }
}
